use crate::history::model::History;
use crate::state::AppState;
use sqlx::Result;
use super::model::SqlID;

#[async_trait]
pub trait IHistory {
  async fn add_item(&self, form: &History) -> sqlx::Result<u64>;
  async fn get_item(&self, id: SqlID) -> sqlx::Result<History>;
  async fn remove_item(&self, id: SqlID) -> sqlx::Result<u64>;
  async fn clear(&self) -> sqlx::Result<u64>;
  async fn list(&self) -> sqlx::Result<Vec<History>>;
}


#[cfg(any(feature = "mysql"))]
#[async_trait]
impl IHistory for AppState {
  async fn add_item(&self, form: &History) -> Result<u64> {
    sqlx::query!(
            r#"
        INSERT INTO history (method, url, params, headers, body, response, create_time)
        VALUES (?, ?, ?, ?, ?, ?, ?)
                "#,
            form.method,
            form.url,
            form.params,
            form.headers,
            form.body,
            form.response,
            form.create_time
        )
      .execute(&self.sql)
      .await
  }

  async fn get_item(&self, id: SqlID) -> Result<History> {
    sqlx::query_as!(
        History,
            r#"
        select id, method, url, params, headers, body, response, create_time from history
        where id = ?
                "#,
            id
        )
      .fetch_one(&self.sql)
      .await
  }

  async fn remove_item(&self, id: SqlID) -> Result<u64> {
    sqlx::query!(
            r#"
        delete from history where id = ?
                "#,
            id
        )
      .execute(&self.sql)
      .await
  }

  async fn clear(&self) -> Result<u64> {
    sqlx::query!(
            r#"
        truncate table history
                "#
        )
      .execute(&self.sql)
      .await
  }

  async fn list(&self) -> Result<Vec<History>> {
    sqlx::query_as!(
        History,
            r#"
        select id, method, url, params, headers, body, response, create_time from history
       order by create_time desc, id desc
                "#
        )
      .fetch_all(&self.sql)
      .await
  }
}

#[cfg(any(feature = "sqlite"))]
#[async_trait]
impl IHistory for AppState {
  async fn add_item(&self, form: &History) -> Result<u64> {
    sqlx::query!(
            r#"
        INSERT INTO history (method, url, params, headers, body, response, create_time)
        VALUES ($1, $2, $3, $4, $5, $6, $7)
                "#,
            form.method,
            form.url,
            form.params,
            form.headers,
            form.body,
            form.response,
            form.create_time
        )
      .execute(&self.sql)
      .await
  }

  async fn get_item(&self, id: SqlID) -> Result<History> {
    sqlx::query_as!(
        History,
            r#"
        select id, method, url, params, headers, body, response, create_time from history
        where id = $1
                "#,
            id
        )
      .fetch_one(&self.sql)
      .await
  }

  async fn remove_item(&self, id: SqlID) -> Result<u64> {
    sqlx::query!(
            r#"
        delete from history where id = $1
                "#,
            id
        )
      .execute(&self.sql)
      .await
  }

  async fn clear(&self) -> Result<u64> {
    sqlx::query!(
            r#"
        delete from history
                "#
        )
      .execute(&self.sql)
      .await
  }

  async fn list(&self) -> Result<Vec<History>> {
    sqlx::query_as!(
        History,
            r#"
        select id, method, url, params, headers, body, response, create_time from history
       order by create_time desc, id desc
                "#
        )
      .fetch_all(&self.sql)
      .await
  }
}
